1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright  1999-2004 The Apache Software Foundation.
7    *
8    *  Licensed under the Apache License, Version 2.0 (the "License");
9    *  you may not use this file except in compliance with the License.
10   *  You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   *  Unless required by applicable law or agreed to in writing, software
15   *  distributed under the License is distributed on an "AS IS" BASIS,
16   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   *  See the License for the specific language governing permissions and
18   *  limitations under the License.
19   *
20   */
21  package com.sun.org.apache.xml.internal.security.signature;
22  
23  
24  
25  import java.io.IOException;
26  import java.io.OutputStream;
27  import java.security.AccessController;
28  import java.security.PrivilegedAction;
29  import java.util.HashSet;
30  import java.util.Set;
31  
32  import com.sun.org.apache.xml.internal.security.algorithms.MessageDigestAlgorithm;
33  import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
34  import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
35  import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
36  import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
37  import com.sun.org.apache.xml.internal.security.transforms.InvalidTransformException;
38  import com.sun.org.apache.xml.internal.security.transforms.Transform;
39  import com.sun.org.apache.xml.internal.security.transforms.TransformationException;
40  import com.sun.org.apache.xml.internal.security.transforms.Transforms;
41  import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces;
42  import com.sun.org.apache.xml.internal.security.utils.Base64;
43  import com.sun.org.apache.xml.internal.security.utils.Constants;
44  import com.sun.org.apache.xml.internal.security.utils.DigesterOutputStream;
45  import com.sun.org.apache.xml.internal.security.utils.IdResolver;
46  import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
47  import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream;
48  import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
49  import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver;
50  import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException;
51  import org.w3c.dom.Attr;
52  import org.w3c.dom.Document;
53  import org.w3c.dom.Element;
54  import org.w3c.dom.Node;
55  import org.w3c.dom.Text;
56  
57  
58  /**
59   * Handles <code>&lt;ds:Reference&gt;</code> elements.
60   *
61   * This includes:
62   *
63   * Constuct a <CODE>ds:Reference</CODE> from an {@link org.w3c.dom.Element}.
64   *
65   * <p>Create a new reference</p>
66   * <pre>
67   * Document _doc;
68   * MessageDigestAlgorithm sha1 = MessageDigestAlgorithm.getInstance("http://#sha1");
69   * Reference ref = new Reference(new XMLSignatureInput(new FileInputStream("1.gif"),
70   *                               "http://localhost/1.gif",
71   *                               (Transforms) null, sha1);
72   * Element refElem = ref.toElement(_doc);
73   * </pre>
74   *
75   * <p>Verify a reference</p>
76   * <pre>
77   * Element refElem = _doc.getElement("Reference"); // PSEUDO
78   * Reference ref = new Reference(refElem);
79   * String url = ref.getURI();
80   * ref.setData(new XMLSignatureInput(new FileInputStream(url)));
81   * if (ref.verify()) {
82   *    System.out.println("verified");
83   * }
84   * </pre>
85   *
86   * <pre>
87   * &lt;element name="Reference" type="ds:ReferenceType"/&gt;
88   *  &lt;complexType name="ReferenceType"&gt;
89   *    &lt;sequence&gt;
90   *      &lt;element ref="ds:Transforms" minOccurs="0"/&gt;
91   *      &lt;element ref="ds:DigestMethod"/&gt;
92   *      &lt;element ref="ds:DigestValue"/&gt;
93   *    &lt;/sequence&gt;
94   *    &lt;attribute name="Id" type="ID" use="optional"/&gt;
95   *    &lt;attribute name="URI" type="anyURI" use="optional"/&gt;
96   *    &lt;attribute name="Type" type="anyURI" use="optional"/&gt;
97   *  &lt;/complexType&gt;
98   * </pre>
99   *
100  * @author Christian Geuer-Pollmann
101  * @see ObjectContainer
102  * @see Manifest
103  */
104 public class Reference extends SignatureElementProxy {
105 
106    /**
107     * Look up useC14N11 system property. If true, an explicit C14N11 transform
108     * will be added if necessary when generating the signature. See section
109     * 3.1.1 of http://www.w3.org/2007/xmlsec/Drafts/xmldsig-core/ for more info.
110     */
111    private static boolean useC14N11 =
112       AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
113          public Boolean run() {
114             return Boolean.getBoolean
115                ("com.sun.org.apache.xml.internal.security.useC14N11");
116          }
117       });
118 
119 /*
120    static {
121       try {
122          useC14N11 = Boolean.getBoolean("com.sun.org.apache.xml.internal.security.useC14N11");
123       } catch (Exception e) {
124          // ignore exceptions
125       }
126    }
127 */
128 
129    /** Field CacheSignedNodes */
130    public final static boolean CacheSignedNodes = false;
131 
132    /** {@link java.util.logging} logging facility */
133     static java.util.logging.Logger log =
134         java.util.logging.Logger.getLogger(Reference.class.getName());
135 
136    /** Field OBJECT_URI */
137    public static final String OBJECT_URI = Constants.SignatureSpecNS
138                                            + Constants._TAG_OBJECT;
139 
140    /** Field MANIFEST_URI */
141    public static final String MANIFEST_URI = Constants.SignatureSpecNS
142                                              + Constants._TAG_MANIFEST;
143    //J-
144    Manifest _manifest = null;
145    XMLSignatureInput _transformsOutput;
146    //J+
147 
148 private Transforms transforms;
149 
150 private Element digestMethodElem;
151 
152 private Element digestValueElement;
153 
154    /**
155     * Constructor Reference
156     *
157     * @param doc the {@link Document} in which <code>XMLsignature</code> is placed
158     * @param BaseURI the URI of the resource where the XML instance will be stored
159     * @param ReferenceURI URI indicate where is data which will digested
160     * @param manifest
161     * @param transforms {@link Transforms} applied to data
162     * @param messageDigestAlgorithm {@link MessageDigestAlgorithm Digest algorithm} which is applied to the data
163     * TODO should we throw XMLSignatureException if MessageDigestAlgoURI is wrong?
164     * @throws XMLSignatureException
165     */
166    protected Reference(Document doc, String BaseURI, String ReferenceURI, Manifest manifest, Transforms transforms, String messageDigestAlgorithm)
167            throws XMLSignatureException {
168 
169       super(doc);
170 
171       XMLUtils.addReturnToElement(this._constructionElement);
172 
173       this._baseURI = BaseURI;
174       this._manifest = manifest;
175 
176       this.setURI(ReferenceURI);
177 
178       // important: The ds:Reference must be added to the associated ds:Manifest
179       //            or ds:SignedInfo _before_ the this.resolverResult() is called.
180       // this._manifest.appendChild(this._constructionElement);
181       // this._manifest.appendChild(this._doc.createTextNode("\n"));
182 
183       if (transforms != null) {
184           this.transforms=transforms;
185          this._constructionElement.appendChild(transforms.getElement());
186          XMLUtils.addReturnToElement(this._constructionElement);
187       }
188       {
189          MessageDigestAlgorithm mda =
190             MessageDigestAlgorithm.getInstance(this._doc,
191                                                messageDigestAlgorithm);
192 
193          digestMethodElem=mda.getElement();
194          this._constructionElement.appendChild(digestMethodElem);
195          XMLUtils.addReturnToElement(this._constructionElement);
196       }
197       {
198          digestValueElement =
199             XMLUtils.createElementInSignatureSpace(this._doc,
200                                                    Constants._TAG_DIGESTVALUE);
201 
202          this._constructionElement.appendChild(digestValueElement);
203          XMLUtils.addReturnToElement(this._constructionElement);
204       }
205    }
206 
207 
208    /**
209     * Build a {@link Reference} from an {@link Element}
210     *
211     * @param element <code>Reference</code> element
212     * @param BaseURI the URI of the resource where the XML instance was stored
213     * @param manifest is the {@link Manifest} of {@link SignedInfo} in which the Reference occurs. We need this because the Manifest has the individual {@link ResourceResolver}s whcih have been set by the user
214     * @throws XMLSecurityException
215     */
216    protected Reference(Element element, String BaseURI, Manifest manifest)
217            throws XMLSecurityException {
218 
219       super(element, BaseURI);
220       this._baseURI=BaseURI;
221       Element el=XMLUtils.getNextElement(element.getFirstChild());
222       if (Constants._TAG_TRANSFORMS.equals(el.getLocalName()) &&
223                   Constants.SignatureSpecNS.equals(el.getNamespaceURI())) {
224           transforms = new Transforms(el,this._baseURI);
225           el=XMLUtils.getNextElement(el.getNextSibling());
226       }
227       digestMethodElem = el;
228       digestValueElement =XMLUtils.getNextElement(digestMethodElem.getNextSibling());;
229       this._manifest = manifest;
230    }
231 
232    /**
233     * Returns {@link MessageDigestAlgorithm}
234     *
235     *
236     * @return {@link MessageDigestAlgorithm}
237     *
238     * @throws XMLSignatureException
239     */
240    public MessageDigestAlgorithm getMessageDigestAlgorithm()
241            throws XMLSignatureException {
242 
243       if (digestMethodElem == null) {
244          return null;
245       }
246 
247       String uri = digestMethodElem.getAttributeNS(null,
248          Constants._ATT_ALGORITHM);
249 
250           if (uri == null) {
251                   return null;
252           }
253 
254       return MessageDigestAlgorithm.getInstance(this._doc, uri);
255    }
256 
257    /**
258     * Sets the <code>URI</code> of this <code>Reference</code> element
259     *
260     * @param URI the <code>URI</code> of this <code>Reference</code> element
261     */
262    public void setURI(String URI) {
263 
264       if ( URI != null) {
265          this._constructionElement.setAttributeNS(null, Constants._ATT_URI,
266                                                   URI);
267       }
268    }
269 
270    /**
271     * Returns the <code>URI</code> of this <code>Reference</code> element
272     *
273     * @return URI the <code>URI</code> of this <code>Reference</code> element
274     */
275    public String getURI() {
276       return this._constructionElement.getAttributeNS(null, Constants._ATT_URI);
277    }
278 
279    /**
280     * Sets the <code>Id</code> attribute of this <code>Reference</code> element
281     *
282     * @param Id the <code>Id</code> attribute of this <code>Reference</code> element
283     */
284    public void setId(String Id) {
285 
286       if ( Id != null ) {
287          this._constructionElement.setAttributeNS(null, Constants._ATT_ID, Id);
288          IdResolver.registerElementById(this._constructionElement, Id);
289       }
290    }
291 
292    /**
293     * Returns the <code>Id</code> attribute of this <code>Reference</code> element
294     *
295     * @return Id the <code>Id</code> attribute of this <code>Reference</code> element
296     */
297    public String getId() {
298       return this._constructionElement.getAttributeNS(null, Constants._ATT_ID);
299    }
300 
301    /**
302     * Sets the <code>type</code> atttibute of the Reference indicate whether an <code>ds:Object</code>, <code>ds:SignatureProperty</code>, or <code>ds:Manifest</code> element
303     *
304     * @param Type the <code>type</code> attribute of the Reference
305     */
306    public void setType(String Type) {
307 
308       if (Type != null) {
309          this._constructionElement.setAttributeNS(null, Constants._ATT_TYPE,
310                                                   Type);
311       }
312    }
313 
314    /**
315     * Return the <code>type</code> atttibute of the Reference indicate whether an <code>ds:Object</code>, <code>ds:SignatureProperty</code>, or <code>ds:Manifest</code> element
316     *
317     * @return the <code>type</code> attribute of the Reference
318     */
319    public String getType() {
320       return this._constructionElement.getAttributeNS(null,
321               Constants._ATT_TYPE);
322    }
323 
324    /**
325     * Method isReferenceToObject
326     *
327     * This returns true if the <CODE>Type</CODE> attribute of the
328     * <CODE>Refernce</CODE> element points to a <CODE>#Object</CODE> element
329     *
330     * @return true if the Reference type indicates that this Reference points to an <code>Object</code>
331     */
332    public boolean typeIsReferenceToObject() {
333 
334       if (Reference.OBJECT_URI.equals(this.getType())) {
335          return true;
336       }
337 
338       return false;
339    }
340 
341    /**
342     * Method isReferenceToManifest
343     *
344     * This returns true if the <CODE>Type</CODE> attribute of the
345     * <CODE>Refernce</CODE> element points to a <CODE>#Manifest</CODE> element
346     *
347     * @return true if the Reference type indicates that this Reference points to a {@link Manifest}
348     */
349    public boolean typeIsReferenceToManifest() {
350 
351       if (Reference.MANIFEST_URI.equals(this.getType())) {
352          return true;
353       }
354 
355       return false;
356    }
357 
358    /**
359     * Method setDigestValueElement
360     *
361     * @param digestValue
362     */
363    private void setDigestValueElement(byte[] digestValue)
364    {
365          Node n=digestValueElement.getFirstChild();
366          while (n!=null) {
367                digestValueElement.removeChild(n);
368                n = n.getNextSibling();
369          }
370 
371          String base64codedValue = Base64.encode(digestValue);
372          Text t = this._doc.createTextNode(base64codedValue);
373 
374          digestValueElement.appendChild(t);
375    }
376 
377    /**
378     * Method generateDigestValue
379     *
380     * @throws ReferenceNotInitializedException
381     * @throws XMLSignatureException
382     */
383    public void generateDigestValue()
384            throws XMLSignatureException, ReferenceNotInitializedException {
385       this.setDigestValueElement(this.calculateDigest(false));
386    }
387 
388    /**
389     * Returns the XMLSignatureInput which is created by de-referencing the URI attribute.
390     * @return the XMLSignatureInput of the source of this reference
391     * @throws ReferenceNotInitializedException If the resolver found any
392     *  problem resolving the reference
393     */
394    public XMLSignatureInput getContentsBeforeTransformation()
395            throws ReferenceNotInitializedException {
396 
397       try {
398          Attr URIAttr = this._constructionElement.getAttributeNodeNS(null,
399             Constants._ATT_URI);
400          String URI;
401 
402          if (URIAttr == null) {
403             URI = null;
404          } else {
405             URI = URIAttr.getNodeValue();
406          }
407 
408          ResourceResolver resolver = ResourceResolver.getInstance(URIAttr,
409             this._baseURI, this._manifest._perManifestResolvers);
410 
411          if (resolver == null) {
412             Object exArgs[] = { URI };
413 
414             throw new ReferenceNotInitializedException(
415                "signature.Verification.Reference.NoInput", exArgs);
416          }
417 
418          resolver.addProperties(this._manifest._resolverProperties);
419 
420          XMLSignatureInput input = resolver.resolve(URIAttr, this._baseURI);
421 
422 
423          return input;
424       }  catch (ResourceResolverException ex) {
425          throw new ReferenceNotInitializedException("empty", ex);
426       } catch (XMLSecurityException ex) {
427          throw new ReferenceNotInitializedException("empty", ex);
428       }
429    }
430 
431    /**
432     * Returns the data which is referenced by the URI attribute. This method
433     * only works works after a call to verify.
434     * @return a XMLSignature with a byte array.
435     * @throws ReferenceNotInitializedException
436     *
437     * @deprecated use getContentsBeforeTransformation
438     */
439    public XMLSignatureInput getTransformsInput() throws ReferenceNotInitializedException
440         {
441                 XMLSignatureInput input=getContentsBeforeTransformation();
442                 XMLSignatureInput result;
443                 try {
444                         result = new XMLSignatureInput(input.getBytes());
445                 } catch (CanonicalizationException ex) {
446                          throw new ReferenceNotInitializedException("empty", ex);
447                 } catch (IOException ex) {
448                          throw new ReferenceNotInitializedException("empty", ex);
449                 }
450                 result.setSourceURI(input.getSourceURI());
451                 return result;
452 
453    }
454 
455    private XMLSignatureInput getContentsAfterTransformation(XMLSignatureInput input, OutputStream os)
456            throws XMLSignatureException {
457 
458       try {
459          Transforms transforms = this.getTransforms();
460          XMLSignatureInput output = null;
461 
462          if (transforms != null) {
463             output = transforms.performTransforms(input,os);
464             this._transformsOutput = output;//new XMLSignatureInput(output.getBytes());
465 
466             //this._transformsOutput.setSourceURI(output.getSourceURI());
467          } else {
468             output = input;
469          }
470 
471          return output;
472       } catch (ResourceResolverException ex) {
473          throw new XMLSignatureException("empty", ex);
474       } catch (CanonicalizationException ex) {
475          throw new XMLSignatureException("empty", ex);
476       } catch (InvalidCanonicalizerException ex) {
477          throw new XMLSignatureException("empty", ex);
478       } catch (TransformationException ex) {
479          throw new XMLSignatureException("empty", ex);
480       } catch (XMLSecurityException ex) {
481          throw new XMLSignatureException("empty", ex);
482       }
483    }
484 
485    /**
486     * Returns the XMLSignatureInput which is the result of the Transforms.
487     * @return a XMLSignatureInput with all transformations applied.
488     * @throws XMLSignatureException
489     */
490    public XMLSignatureInput getContentsAfterTransformation()
491            throws XMLSignatureException {
492 
493       XMLSignatureInput input = this.getContentsBeforeTransformation();
494 
495       return this.getContentsAfterTransformation(input, null);
496    }
497 
498    /**
499     * This method returns the XMLSignatureInput which represents the node set before
500     * some kind of canonicalization is applied for the first time.
501     * @return Gets a the node doing everything till the first c14n is needed
502     *
503     * @throws XMLSignatureException
504     */
505    public XMLSignatureInput getNodesetBeforeFirstCanonicalization()
506            throws XMLSignatureException {
507 
508       try {
509          XMLSignatureInput input = this.getContentsBeforeTransformation();
510          XMLSignatureInput output = input;
511          Transforms transforms = this.getTransforms();
512 
513          if (transforms != null) {
514             doTransforms: for (int i = 0; i < transforms.getLength(); i++) {
515                Transform t = transforms.item(i);
516                String URI = t.getURI();
517 
518                if (URI.equals(Transforms
519                        .TRANSFORM_C14N_EXCL_OMIT_COMMENTS) || URI
520                           .equals(Transforms
521                              .TRANSFORM_C14N_EXCL_WITH_COMMENTS) || URI
522                                 .equals(Transforms
523                                    .TRANSFORM_C14N_OMIT_COMMENTS) || URI
524                                       .equals(Transforms
525                                          .TRANSFORM_C14N_WITH_COMMENTS)) {
526 
527                   break doTransforms;
528                }
529 
530                output = t.performTransform(output, null);
531             }
532 
533             output.setSourceURI(input.getSourceURI());
534          }
535          return output;
536       } catch (IOException ex) {
537          throw new XMLSignatureException("empty", ex);
538       } catch (ResourceResolverException ex) {
539          throw new XMLSignatureException("empty", ex);
540       } catch (CanonicalizationException ex) {
541          throw new XMLSignatureException("empty", ex);
542       } catch (InvalidCanonicalizerException ex) {
543          throw new XMLSignatureException("empty", ex);
544       } catch (TransformationException ex) {
545          throw new XMLSignatureException("empty", ex);
546       } catch (XMLSecurityException ex) {
547          throw new XMLSignatureException("empty", ex);
548       }
549    }
550 
551    /**
552     * Method getHTMLRepresentation
553     * @return The HTML of the transformation
554     * @throws XMLSignatureException
555     */
556    public String getHTMLRepresentation() throws XMLSignatureException {
557 
558       try {
559          XMLSignatureInput nodes = this.getNodesetBeforeFirstCanonicalization();
560          Set inclusiveNamespaces = new HashSet();
561 
562          {
563             Transforms transforms = this.getTransforms();
564             Transform c14nTransform = null;
565 
566             if (transforms != null) {
567                doTransforms: for (int i = 0; i < transforms.getLength(); i++) {
568                   Transform t = transforms.item(i);
569                   String URI = t.getURI();
570 
571                   if (URI.equals(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS)
572                           || URI.equals(
573                              Transforms.TRANSFORM_C14N_EXCL_WITH_COMMENTS)) {
574                      c14nTransform = t;
575 
576                      break doTransforms;
577                   }
578                }
579             }
580 
581             if (c14nTransform != null) {
582 
583                if (c14nTransform
584                        .length(InclusiveNamespaces
585                           .ExclusiveCanonicalizationNamespace, InclusiveNamespaces
586                           ._TAG_EC_INCLUSIVENAMESPACES) == 1) {
587 
588                   // there is one InclusiveNamespaces element
589                   InclusiveNamespaces in = new InclusiveNamespaces(
590                         XMLUtils.selectNode(
591                         c14nTransform.getElement().getFirstChild(),
592                                                 InclusiveNamespaces.ExclusiveCanonicalizationNamespace,
593                         InclusiveNamespaces._TAG_EC_INCLUSIVENAMESPACES,0), this.getBaseURI());
594 
595                   inclusiveNamespaces = InclusiveNamespaces.prefixStr2Set(
596                      in.getInclusiveNamespaces());
597                }
598             }
599          }
600 
601          return nodes.getHTMLRepresentation(inclusiveNamespaces);
602       } catch (TransformationException ex) {
603          throw new XMLSignatureException("empty", ex);
604       } catch (InvalidTransformException ex) {
605          throw new XMLSignatureException("empty", ex);
606       } catch (XMLSecurityException ex) {
607          throw new XMLSignatureException("empty", ex);
608       }
609    }
610 
611    /**
612     * This method only works works after a call to verify.
613     * @return the transformed output(i.e. what is going to be digested).
614     */
615    public XMLSignatureInput getTransformsOutput() {
616       return this._transformsOutput;
617    }
618 
619    /**
620     * This method returns the {@link XMLSignatureInput} which is referenced by the
621     * <CODE>URI</CODE> Attribute.
622     * @param os where to write the transformation can be null.
623     * @return the element to digest
624     *
625     * @throws XMLSignatureException
626     * @see Manifest#verifyReferences()
627     */
628    protected XMLSignatureInput dereferenceURIandPerformTransforms(OutputStream os)
629            throws XMLSignatureException {
630 
631       try {
632          XMLSignatureInput input = this.getContentsBeforeTransformation();
633          XMLSignatureInput output = this.getContentsAfterTransformation(input, os);
634 
635          /* at this stage, this._transformsInput and this._transformsOutput
636           * contain a huge amount of nodes. When we do not cache these nodes
637           * but only preserve the octets, the memory footprint is dramatically
638           * reduced.
639           */
640          if (!Reference.CacheSignedNodes) {
641 
642             this._transformsOutput = output;//new XMLSignatureInput(output.getBytes());
643 
644             //this._transformsOutput.setSourceURI(output.getSourceURI());
645          }
646          return output;
647       } catch (XMLSecurityException ex) {
648          throw new ReferenceNotInitializedException("empty", ex);
649       }
650    }
651 
652    /**
653     * Method getTransforms
654     *
655     * @return The transforms that applied this reference.
656     * @throws InvalidTransformException
657     * @throws TransformationException
658     * @throws XMLSecurityException
659     * @throws XMLSignatureException
660     */
661    public Transforms getTransforms()
662            throws XMLSignatureException, InvalidTransformException,
663                   TransformationException, XMLSecurityException {
664 
665       return transforms;
666    }
667 
668    /**
669     * Method getReferencedBytes
670     *
671     * @return the bytes that will be used to generated digest.
672     * @throws ReferenceNotInitializedException
673     * @throws XMLSignatureException
674     */
675    public byte[] getReferencedBytes()
676            throws ReferenceNotInitializedException, XMLSignatureException {
677     try {
678         XMLSignatureInput output=this.dereferenceURIandPerformTransforms(null);
679 
680         byte[] signedBytes = output.getBytes();
681 
682         return signedBytes;
683      } catch (IOException ex) {
684         throw new ReferenceNotInitializedException("empty", ex);
685      } catch (CanonicalizationException ex) {
686         throw new ReferenceNotInitializedException("empty", ex);
687      }
688 
689    }
690 
691 
692    /**
693     * Method calculateDigest
694     *
695     * @param validating true if validating the reference
696     * @return reference Calculate the digest of this reference.
697     * @throws ReferenceNotInitializedException
698     * @throws XMLSignatureException
699     */
700    private byte[] calculateDigest(boolean validating)
701            throws ReferenceNotInitializedException, XMLSignatureException {
702 
703       try {
704 
705          MessageDigestAlgorithm mda = this.getMessageDigestAlgorithm();
706 
707          mda.reset();
708          DigesterOutputStream diOs=new DigesterOutputStream(mda);
709          OutputStream os=new UnsyncBufferedOutputStream(diOs);
710          XMLSignatureInput output=this.dereferenceURIandPerformTransforms(os);
711          // if signing and c14n11 property == true explicitly add
712          // C14N11 transform if needed
713          if (this.useC14N11 && !validating &&
714              !output.isOutputStreamSet() && !output.isOctetStream()) {
715              if (transforms == null) {
716                  transforms = new Transforms(this._doc);
717                  this._constructionElement.insertBefore
718                      (transforms.getElement(), digestMethodElem);
719              }
720              transforms.addTransform(Transforms.TRANSFORM_C14N11_OMIT_COMMENTS);
721              output.updateOutputStream(os, true);
722          } else {
723              output.updateOutputStream(os);
724          }
725          os.flush();
726          //this.getReferencedBytes(diOs);
727          //mda.update(data);
728 
729          return diOs.getDigestValue();
730       } catch (XMLSecurityException ex) {
731          throw new ReferenceNotInitializedException("empty", ex);
732       } catch (IOException ex) {
733          throw new ReferenceNotInitializedException("empty", ex);
734       }
735    }
736 
737    /**
738     * Returns the digest value.
739     *
740     * @return the digest value.
741     * @throws Base64DecodingException if Reference contains no proper base64 encoded data.
742     * @throws XMLSecurityException if the Reference does not contain a DigestValue element
743     */
744    public byte[] getDigestValue() throws Base64DecodingException, XMLSecurityException {
745       if (digestValueElement == null) {
746                   // The required element is not in the XML!
747                   Object[] exArgs ={ Constants._TAG_DIGESTVALUE,
748                                                          Constants.SignatureSpecNS };
749                   throw new XMLSecurityException(
750                                         "signature.Verification.NoSignatureElement",
751                                         exArgs);
752           }
753       byte[] elemDig = Base64.decode(digestValueElement);
754       return elemDig;
755    }
756 
757 
758    /**
759     * Tests reference valdiation is success or false
760     *
761     * @return true if reference valdiation is success, otherwise false
762     * @throws ReferenceNotInitializedException
763     * @throws XMLSecurityException
764     */
765    public boolean verify()
766            throws ReferenceNotInitializedException, XMLSecurityException {
767 
768       byte[] elemDig = this.getDigestValue();
769       byte[] calcDig = this.calculateDigest(true);
770       boolean equal = MessageDigestAlgorithm.isEqual(elemDig, calcDig);
771 
772       if (!equal) {
773          log.log(java.util.logging.Level.WARNING, "Verification failed for URI \"" + this.getURI() + "\"");
774          log.log(java.util.logging.Level.WARNING, "Expected Digest: " + Base64.encode(elemDig));
775          log.log(java.util.logging.Level.WARNING, "Actual Digest: " + Base64.encode(calcDig));
776       } else {
777          log.log(java.util.logging.Level.INFO, "Verification successful for URI \"" + this.getURI() + "\"");
778       }
779 
780       return equal;
781    }
782 
783    /**
784     * Method getBaseLocalName
785     * @inheritDoc
786     *
787     */
788    public String getBaseLocalName() {
789       return Constants._TAG_REFERENCE;
790    }
791 }